﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using PIT.Labs.ProjectRepository.Owl2DotNet.Parsers;

using System.Xml.Schema;
using System.Xml.Linq;
using System.Xml;

namespace PIT.Labs.ProjectRepository.Owl2DotNet.Xsd
{
    /// <summary>
    /// Parser for ontologies from xsd files
    /// </summary>
    public class XsdXmlParser : OntologyParserBase
    {
        static XNamespace xsd = "http://www.w3.org/2001/XMLSchema";
        static XName element = xsd + "element";
        static XName complexType = xsd + "complexType";
        static XName simpleType = xsd + "simpleType";
        static XName sequence = xsd + "sequence";
        static XName attribute = xsd + "attribute";

        private static string NameToQualified(XDocument doc, string name)
        {
            var parts = name.Split(':');
            if (parts.Length > 1)
            {
                XNamespace nsp = doc.Root.GetNamespaceOfPrefix(parts[0]);
                return nsp.NamespaceName + "#" + parts[1];
            }else{
                return doc.Root.Attribute("targetNamespace").Value + "#" + name;
            }
        }

        private Uri NameToUri(XDocument doc, string name)
        {
            return new Uri(NameToQualified(doc, name));
        }

        /// <summary>
        /// Parse ontology from stream
        /// </summary>
        /// <param name="instream"></param>
        /// <returns></returns>
        public override IOntology Load(System.IO.Stream instream)
        {
            XmlReader xmlFromStream = XmlReader.Create(instream, new XmlReaderSettings() { ProhibitDtd = false });
            var xmlDoc = XDocument.Load(xmlFromStream);

            var rootNamespace = xmlDoc.Root.Attribute("targetNamespace").Value;

            var ontology = new XsdOntology(rootNamespace);

            var compTypes = new Dictionary<string, XElement>();


            foreach (var item in xmlDoc.Descendants(complexType).Where(x => x.Attribute("name") != null))
            {
                new XsdClass(ontology, NameToQualified(xmlDoc, item.Attribute("name").Value), item);
            }

            foreach (var item in xmlDoc.Descendants(simpleType).Where(x => x.Attribute("name") != null))
            {
                new XsdDataType(ontology, NameToQualified(xmlDoc, item.Attribute("name").Value), item);
            }

            foreach (var item in xmlDoc.Descendants(element).Where(x => x.Attribute("name") != null))
            {
                if (item.Elements(sequence).Count() != 0 || item.Elements(attribute).Count() != 0)
                {
                    XsdClass c = new XsdClass(ontology, NameToQualified(xmlDoc, item.Attribute("name").Value), item);

                    foreach (var attr in item.Elements(sequence).Elements(element).Where(x=>x.Attribute("name")!=null))
                    {
                        new XsdObjectProperty(ontology, NameToQualified(xmlDoc, attr.Attribute("name").Value), c, item);
                    }
                    foreach (var attr in item.Elements(attribute).Where(x=>x.Attribute("name")!=null))
                    {
                        new XsdObjectProperty(ontology, NameToQualified(xmlDoc, attr.Attribute("name").Value), c, item);
                    }
                }
                else
                {
                    new XsdDataProperty(ontology, NameToQualified(xmlDoc, item.Attribute("name").Value), item);
                }
            }
            
            return ontology;
        }

        /// <summary>
        /// Debug Method
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        public static void ValidationCallbackOne(object sender, ValidationEventArgs args)
        {
            Console.WriteLine(args.Message);
        }
    }
}
